#include <stdio.h>
#include <math.h>
#include <graphics.h> 
typedef struct _Point3D
{
 float x;
 float y;
 float z;
 float w;
}Point3D;

/*原点位置 */
int middleX,middleY;
 

/* Point3D的有关函数: */
/*  Point3D的赋值函数1 */
void EvaPoint3D(Point3D * pDestPoint, float x, float y, float z)
{
 pDestPoint->x = x;
 pDestPoint->y = y;
 pDestPoint->z = z;
 pDestPoint->w = 1.0f;
}
/*  Point3D的赋值函数2 */
void EvaPoint3D2(Point3D * pDestPoint, Point3D * pSrcPoint)
{ 
 float  temp = 1 / pSrcPoint->w;
 EvaPoint3D(pDestPoint, pSrcPoint->x * temp, pSrcPoint->y * temp, pSrcPoint->z * temp);
}
/* Matrix3D结构体:
 */typedef struct _Matrix3D
{
 float  f00,f01,f02,f03; /* 为什么不直接定义 float [4][4]呢? */
 float  f10,f11,f12,f13; /* 嘻嘻!     */
 float  f20,f21,f22,f23;
 float  f30,f31,f32,f33;
}Matrix3D;
/* 与Matrix3D有关的函数,如下: */
/*  matrix3D的赋值函数1 */
void EvaMatrix3D(Matrix3D * pDestMatrix, float f00, float f01, float f02,float f03,
                                         float f10, float f11, float f12,float f13,
                                         float f20, float f21, float f22,float f23,
                                         float f30, float f31, float f32,float f33)
{   
 pDestMatrix->f00 = f00;   pDestMatrix->f01 = f01;   pDestMatrix->f02 = f02;   pDestMatrix->f03 = f03;
 pDestMatrix->f10 = f10;   pDestMatrix->f11 = f11;   pDestMatrix->f12 = f12;   pDestMatrix->f13 = f13;
 pDestMatrix->f20 = f20;   pDestMatrix->f21 = f21;   pDestMatrix->f22 = f22;   pDestMatrix->f23 = f23;
 pDestMatrix->f30 = f30;   pDestMatrix->f31 = f31;   pDestMatrix->f32 = f32;   pDestMatrix->f33 = f33;
}
/*  matrix3D的赋值函数2 */
void EvaMatrix3D2(Matrix3D * pDestMatrix, Matrix3D * pSrcMatrix)
{
 EvaMatrix3D(pDestMatrix, pSrcMatrix->f00, pSrcMatrix->f01, pSrcMatrix->f02, pSrcMatrix->f03,
                          pSrcMatrix->f10, pSrcMatrix->f11, pSrcMatrix->f12, pSrcMatrix->f13,
                          pSrcMatrix->f20, pSrcMatrix->f21, pSrcMatrix->f22, pSrcMatrix->f23,
                          pSrcMatrix->f30, pSrcMatrix->f31, pSrcMatrix->f32, pSrcMatrix->f33);
}
/* Matrix3D与Point3D相乘  */
void MatrixPointMul(Point3D * pDestPoint, Matrix3D * pSrcMatrix, Point3D * pSrcPoint)
{
 Point3D temp;
 temp.x = pSrcMatrix->f00 * pSrcPoint->x + pSrcMatrix->f01 * pSrcPoint->y + pSrcMatrix->f02 * pSrcPoint->z + pSrcMatrix->f03 * pSrcPoint->w;
 temp.y = pSrcMatrix->f10 * pSrcPoint->x + pSrcMatrix->f11 * pSrcPoint->y + pSrcMatrix->f12 * pSrcPoint->z + pSrcMatrix->f13 * pSrcPoint->w;
 temp.z = pSrcMatrix->f20 * pSrcPoint->x + pSrcMatrix->f21 * pSrcPoint->y + pSrcMatrix->f22 * pSrcPoint->z + pSrcMatrix->f23 * pSrcPoint->w;
 temp.w = pSrcMatrix->f30 * pSrcPoint->x + pSrcMatrix->f31 * pSrcPoint->y + pSrcMatrix->f32 * pSrcPoint->z + pSrcMatrix->f33 * pSrcPoint->w;
 EvaPoint3D2(pDestPoint,&temp);
}
/* Matrix3D与Matrix3D相乘  */
void MatrixMul(Matrix3D * pDestMatrix, Matrix3D * pSrcMatrix1, Matrix3D * pSrcMatrix2)
{
 Matrix3D temp;
   temp.f00= pSrcMatrix1->f00 * pSrcMatrix2->f00 + pSrcMatrix1->f01 * pSrcMatrix2->f10 + pSrcMatrix1->f02 * pSrcMatrix2->f20 + pSrcMatrix1->f03 * pSrcMatrix2->f30;
 temp.f01= pSrcMatrix1->f00 * pSrcMatrix2->f01 + pSrcMatrix1->f01 * pSrcMatrix2->f11 + pSrcMatrix1->f02 * pSrcMatrix2->f21 + pSrcMatrix1->f03 * pSrcMatrix2->f31;
   temp.f02= pSrcMatrix1->f00 * pSrcMatrix2->f02 + pSrcMatrix1->f01 * pSrcMatrix2->f12 + pSrcMatrix1->f02 * pSrcMatrix2->f22 + pSrcMatrix1->f03 * pSrcMatrix2->f32;
   temp.f03= pSrcMatrix1->f00 * pSrcMatrix2->f03 + pSrcMatrix1->f01 * pSrcMatrix2->f13 + pSrcMatrix1->f02 * pSrcMatrix2->f23 + pSrcMatrix1->f03 * pSrcMatrix2->f33;
   temp.f10= pSrcMatrix1->f10 * pSrcMatrix2->f00 + pSrcMatrix1->f11 * pSrcMatrix2->f10 + pSrcMatrix1->f12 * pSrcMatrix2->f20 + pSrcMatrix1->f13 * pSrcMatrix2->f30;
   temp.f11= pSrcMatrix1->f10 * pSrcMatrix2->f01 + pSrcMatrix1->f11 * pSrcMatrix2->f11 + pSrcMatrix1->f12 * pSrcMatrix2->f21 + pSrcMatrix1->f13 * pSrcMatrix2->f31;
   temp.f12= pSrcMatrix1->f10 * pSrcMatrix2->f02 + pSrcMatrix1->f11 * pSrcMatrix2->f12 + pSrcMatrix1->f12 * pSrcMatrix2->f22 + pSrcMatrix1->f13 * pSrcMatrix2->f32;
   temp.f13= pSrcMatrix1->f10 * pSrcMatrix2->f03 + pSrcMatrix1->f11 * pSrcMatrix2->f13 + pSrcMatrix1->f12 * pSrcMatrix2->f23 + pSrcMatrix1->f13 * pSrcMatrix2->f33;
   temp.f20= pSrcMatrix1->f20 * pSrcMatrix2->f00 + pSrcMatrix1->f21 * pSrcMatrix2->f10 + pSrcMatrix1->f22 * pSrcMatrix2->f20 + pSrcMatrix1->f23 * pSrcMatrix2->f30;
   temp.f21= pSrcMatrix1->f20 * pSrcMatrix2->f01 + pSrcMatrix1->f21 * pSrcMatrix2->f11 + pSrcMatrix1->f22 * pSrcMatrix2->f21 + pSrcMatrix1->f23 * pSrcMatrix2->f31;
   temp.f22= pSrcMatrix1->f20 * pSrcMatrix2->f02 + pSrcMatrix1->f21 * pSrcMatrix2->f12 + pSrcMatrix1->f22 * pSrcMatrix2->f22 + pSrcMatrix1->f23 * pSrcMatrix2->f32;
   temp.f23= pSrcMatrix1->f20 * pSrcMatrix2->f03 + pSrcMatrix1->f21 * pSrcMatrix2->f13 + pSrcMatrix1->f22 * pSrcMatrix2->f23 + pSrcMatrix1->f23 * pSrcMatrix2->f33;
   temp.f30= pSrcMatrix1->f30 * pSrcMatrix2->f00 + pSrcMatrix1->f31 * pSrcMatrix2->f10 + pSrcMatrix1->f32 * pSrcMatrix2->f20 + pSrcMatrix1->f33 * pSrcMatrix2->f30;
   temp.f31= pSrcMatrix1->f30 * pSrcMatrix2->f01 + pSrcMatrix1->f31 * pSrcMatrix2->f11 + pSrcMatrix1->f32 * pSrcMatrix2->f21 + pSrcMatrix1->f33 * pSrcMatrix2->f31;
   temp.f32= pSrcMatrix1->f30 * pSrcMatrix2->f02 + pSrcMatrix1->f31 * pSrcMatrix2->f12 + pSrcMatrix1->f32 * pSrcMatrix2->f22 + pSrcMatrix1->f33 * pSrcMatrix2->f32;
   temp.f33= pSrcMatrix1->f30 * pSrcMatrix2->f03 + pSrcMatrix1->f31 * pSrcMatrix2->f13 + pSrcMatrix1->f32 * pSrcMatrix2->f23 + pSrcMatrix1->f33 * pSrcMatrix2->f33;
 
 EvaMatrix3D2(pDestMatrix, &temp);
}
/* 平移矩阵函数 */
void TranslationMatrix(Matrix3D * pDestMatrix, float tx, float ty, float tz)
{
 EvaMatrix3D(pDestMatrix,1, 0, 0, tx,
                         0, 1, 0, ty,
                         0, 0, 1, tz,
                         0, 0, 0, 1);
}
/* 绕Y轴旋转矩阵 */
void RotationMatrixY(Matrix3D * pDestMatrix, float angle)
{
 float sn,cs;
 sn=(float)sin(angle);
 cs=(float)cos(angle);
 EvaMatrix3D(pDestMatrix, cs,  0, sn,  0,
                           0,  1,  0,  0,
                         -sn,  0, cs,  0,
                           0,  0,  0,  1);
}
/* 3D的图元是三角形，所以少了它没那么方便，定义一个三角形的结构体: */
typedef struct _Triangle3D
{
 Point3D p1; /* triangle3D 的三个点 */
 Point3D p2;
 Point3D p3;
}Triangle3D;
/* 还有它的一些函数: */
/*  Triangle3D的赋值函数  */
void EvaTriangle3D(Triangle3D * pDestTriangle, Point3D * p1, Point3D * p2, Point3D * p3)
{ 
 EvaPoint3D2(&(pDestTriangle->p1), p1);
 EvaPoint3D2(&(pDestTriangle->p2), p2);
 EvaPoint3D2(&(pDestTriangle->p3), p3);
}
/* Matrix3D与Triangle3D相乘  */
void MatrixTriangleMul(Triangle3D * pDestTriangle, Matrix3D * pSrcMatrix, Triangle3D * pSrcTriangle)
{
 MatrixPointMul(&(pDestTriangle->p1), pSrcMatrix, &(pSrcTriangle->p1));
 MatrixPointMul(&(pDestTriangle->p2), pSrcMatrix, &(pSrcTriangle->p2));
 MatrixPointMul(&(pDestTriangle->p3), pSrcMatrix, &(pSrcTriangle->p3));
}
/* 为了简单起见，直接建一个简单的投影viewMarix,如下: */
#define  DISTANCE -150.0f  /* 后投影面的距离  */
Matrix3D viewMatrix = {1.0f, 0.0f, 0.0f,    0.0f,
                       0.0f, 1.0f, 0.0f,    0.0f,
                       0.0f, 0.0f, 1.0f,    0.0f,
                       0.0f, 0.0f, 1.0f/DISTANCE,  0.0f};
/* 原理很简单，通过这个矩阵将所有点都投影到 z == -50 的平面上.
另外还要定义视点的位置: */
Point3D  eyePosition = {0.0f, 0.0f, 50.0f, 1.0f}; /*x == 0.0f, y == 0.0f, z == 50.0f*/
/* 所以再加了一个初始化viewMatrix的函数: */
/* 初始化viewMatrix */
void InitViewMatrix()
{
 Matrix3D translation;
 TranslationMatrix(&translation, -eyePosition.x, -eyePosition.y, -eyePosition.z);  
 MatrixMul(&viewMatrix, &viewMatrix, &translation);
}
/* 加一个有关投影Triangle3D并画出三角形的函数: */
/* 画线函数 */
void line3D(Point3D * p1, Point3D * p2) 
{
 line(p1->x + middleX, middleY - p1->y, p2->x + middleX, middleY - p2->y);
}
/* 其中的middleX,middleY是int型全局变量,在main()中赋值,如下,为屏幕中点的x,y坐标: */
/* 规范化Point3D函数 */
void UniformPoint(Point3D * pDestPoint, Point3D * pSrcPoint)
{
 float  t = 1.0f / pSrcPoint->w;
 EvaPoint3D(pDestPoint, pSrcPoint->x * t, pSrcPoint->y * t, pSrcPoint->z * t);
}
/* Triangle3D的投影函数 */
void TriangleProject(Triangle3D * triangle)
{
 Point3D  temp1,temp2,temp3;
 MatrixPointMul(&temp1, &viewMatrix, &(triangle->p1)); /*三角形的三个点分别与viewMatrix相乘*/
 MatrixPointMul(&temp2, &viewMatrix, &(triangle->p2));
 MatrixPointMul(&temp3, &viewMatrix, &(triangle->p3));
 UniformPoint(&temp1, &temp1);  /*规范化*/
 UniformPoint(&temp2, &temp2);
 UniformPoint(&temp3, &temp3);
 line3D(&temp1, &temp2);   /*画三角形的三条边*/
 line3D(&temp2, &temp3);
 line3D(&temp3, &temp1);
}
/* 好啦，万事俱备，只欠东风了,
定义main函数: */
void main()
{
 Point3D  pointOfCube[8];       /*立方体有八个点*/
 Triangle3D triangleOfCube[12]; /*立方体有六个面，每个面可以分成两个三角形，所以.......*/
 Matrix3D rotationMatrix;       /*旋转矩阵*/
 int   i = 0;   
 char   c = ' ';
 int gdriver=DETECT,gmode;
 registerbgidriver(EGAVGA_driver);
 initgraph(&gdriver,&gmode,0);
 setlinestyle(SOLID_LINE, USERBIT_LINE, THICK_WIDTH);
 setbkcolor(BLUE);
 
 middleX = getmaxx()/2;
 middleY = getmaxy()/2;
 InitViewMatrix();
#define LENGTH 20.0f  /*立方体的边长*/
 EvaPoint3D(&pointOfCube[0],  LENGTH,  LENGTH, LENGTH);
 EvaPoint3D(&pointOfCube[1], -LENGTH,  LENGTH, LENGTH);
 EvaPoint3D(&pointOfCube[2],  LENGTH, -LENGTH, LENGTH);
 EvaPoint3D(&pointOfCube[3], -LENGTH, -LENGTH, LENGTH);
 EvaPoint3D(&pointOfCube[4],  LENGTH,  LENGTH, -LENGTH);
 EvaPoint3D(&pointOfCube[5], -LENGTH,  LENGTH, -LENGTH);
 EvaPoint3D(&pointOfCube[6],  LENGTH, -LENGTH, -LENGTH);
 EvaPoint3D(&pointOfCube[7], -LENGTH, -LENGTH, -LENGTH);
 EvaTriangle3D(&triangleOfCube[0], &pointOfCube[0], &pointOfCube[1], &pointOfCube[2]);
 EvaTriangle3D(&triangleOfCube[1], &pointOfCube[1], &pointOfCube[2], &pointOfCube[3]);
 EvaTriangle3D(&triangleOfCube[2], &pointOfCube[4], &pointOfCube[5], &pointOfCube[6]);
 EvaTriangle3D(&triangleOfCube[3], &pointOfCube[5], &pointOfCube[6], &pointOfCube[7]);
 EvaTriangle3D(&triangleOfCube[4], &pointOfCube[0], &pointOfCube[2], &pointOfCube[4]);
 EvaTriangle3D(&triangleOfCube[5], &pointOfCube[2], &pointOfCube[4], &pointOfCube[6]);
 EvaTriangle3D(&triangleOfCube[6], &pointOfCube[1], &pointOfCube[3], &pointOfCube[5]);
 EvaTriangle3D(&triangleOfCube[7], &pointOfCube[3], &pointOfCube[5], &pointOfCube[7]);
 EvaTriangle3D(&triangleOfCube[8], &pointOfCube[0], &pointOfCube[1], &pointOfCube[4]);
 EvaTriangle3D(&triangleOfCube[9], &pointOfCube[1], &pointOfCube[4], &pointOfCube[5]);
 EvaTriangle3D(&triangleOfCube[10], &pointOfCube[2], &pointOfCube[3], &pointOfCube[6]);
 EvaTriangle3D(&triangleOfCube[11], &pointOfCube[3], &pointOfCube[6], &pointOfCube[7]);
 RotationMatrixY(&rotationMatrix, 0.07f);
 
 
 while(1)
 {
  cleardevice();  /* 清屏 */
  
  for(i = 0; i < 12; i++) /* 投影所有三角形  */
  { 
   TriangleProject(&triangleOfCube[i]); 
  }
  c = getch();
  if('e' == c || 'E' == c)  /*按 e 键退出*/
  {
   exit(0);
  }
  for(i = 0; i < 12; i++) /* 旋转所有三角形  */
  {
   MatrixTriangleMul(&triangleOfCube[i], &rotationMatrix, &triangleOfCube[i]);
  }
 }
}